package main

import (
	"fmt"
	"os"
	"strconv"
	"syscall"
	"unsafe"

	"github.com/lxn/win"
)

var (
	gdiplus               = syscall.NewLazyDLL("gdiplus.dll")
	gdiplusStartup        = gdiplus.NewProc("GdiplusStartup")
	gdiplusShutdown       = gdiplus.NewProc("GdiplusShutdown")
	gdipCreateFromImage   = gdiplus.NewProc("GdipCreateFromImage")
	gdipLoadImageFromFile = gdiplus.NewProc("GdipLoadImageFromFile")
	gdipGetImageWidth     = gdiplus.NewProc("GdipGetImageWidth")
	gdipGetImageHeight    = gdiplus.NewProc("GdipGetImageHeight")
	gdipDeleteGraphics    = gdiplus.NewProc("GdipDeleteGraphics")
	gdipDisposeImage      = gdiplus.NewProc("GdipDisposeImage")
	gdipDrawImageRectI    = gdiplus.NewProc("GdipDrawImageRectI")
	gdipCreateFromHDC     = gdiplus.NewProc("GdipCreateFromHDC")

	winspool         = syscall.NewLazyDLL("winspool.drv")
	openPrinter      = winspool.NewProc("OpenPrinterW")
	startDocPrinter  = winspool.NewProc("StartDocPrinterW")
	startPagePrinter = winspool.NewProc("StartPagePrinter")
	endPagePrinter   = winspool.NewProc("EndPagePrinter")
	endDocPrinter    = winspool.NewProc("EndDocPrinter")
	closePrinter     = winspool.NewProc("ClosePrinter")
)

type GdiplusStartupInput struct {
	GdiplusVersion           uint32
	DebugEventCallback       uintptr
	SuppressBackgroundThread bool
	SuppressExternalCodecs   bool
}

func main() {
	// 参数1是文件地址，参数2是打印机名称
	if len(os.Args) < 3 {
		fmt.Println("用法: printer.exe <图片路径> <打印机名称>")
		return
	}

	imagePath := os.Args[1]
	printerName := os.Args[2]

	// Parse optional parameters with defaults
	destX := 12
	destY := 12
	destWidth := 310
	destHeight := 310

	if len(os.Args) > 3 {
		if x, err := strconv.Atoi(os.Args[3]); err == nil {
			destX = x
		}
	}
	if len(os.Args) > 4 {
		if y, err := strconv.Atoi(os.Args[4]); err == nil {
			destY = y
		}
	}
	if len(os.Args) > 5 {
		if w, err := strconv.Atoi(os.Args[5]); err == nil {
			destWidth = w
		}
	}
	if len(os.Args) > 6 {
		if h, err := strconv.Atoi(os.Args[6]); err == nil {
			destHeight = h
		}
	}
	fmt.Println(destX, destY, destWidth, destHeight)
	if err := PrintImage(imagePath, printerName, destX, destY, destWidth, destHeight); err != nil {
		fmt.Println("打印失败:", err)
		return
	}

	fmt.Println("打印成功")
}

func PrintImage(imagePath string, printerName string, destX, destY, destWidth, destHeight int) error {
	// 初始化GDI+
	var token uintptr
	startup := GdiplusStartupInput{GdiplusVersion: 1}
	status, _, _ := gdiplusStartup.Call(
		uintptr(unsafe.Pointer(&token)),
		uintptr(unsafe.Pointer(&startup)),
		0,
	)
	if status != 0 {
		return fmt.Errorf("无法初始化GDI+: %v", status)
	}
	defer gdiplusShutdown.Call(token)

	// 加载图片
	var image uintptr
	status, _, _ = gdipLoadImageFromFile.Call(
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(imagePath))),
		uintptr(unsafe.Pointer(&image)),
	)
	if status != 0 {
		return fmt.Errorf("无法加载图片: %v", status)
	}
	defer gdipDisposeImage.Call(image)

	// 获取图片尺寸
	var width, height uint32
	status, _, _ = gdipGetImageWidth.Call(image, uintptr(unsafe.Pointer(&width)))
	if status != 0 {
		return fmt.Errorf("无法获取图片宽度: %v", status)
	}
	status, _, _ = gdipGetImageHeight.Call(image, uintptr(unsafe.Pointer(&height)))
	if status != 0 {
		return fmt.Errorf("无法获取图片高度: %v", status)
	}

	// 打开打印机
	var hPrinter uintptr
	ret, _, _ := openPrinter.Call(
		uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(printerName))),
		uintptr(unsafe.Pointer(&hPrinter)),
		0,
	)
	if ret == 0 {
		return fmt.Errorf("无法打开打印机")
	}
	defer closePrinter.Call(hPrinter)
	fmt.Println(win.DMPAPER_USER)
	// 设置打印机参数
	var devMode win.DEVMODE
	devMode.DmSize = uint16(unsafe.Sizeof(win.DEVMODE{}))
	devMode.DmFields = win.DM_PAPERSIZE | win.DM_PAPERLENGTH | win.DM_PAPERWIDTH | win.DM_PRINTQUALITY
	devMode.DmPaperSize = win.DMPAPER_USER // 自定义纸张大小
	devMode.DmPaperLength = 1600           // 80mm * 10 (转换为0.1mm单位)
	devMode.DmPaperWidth = 1600            // 80mm * 10
	devMode.DmPrintQuality = 203           // 203 DPI

	// 创建打印机DC并应用设置
	printerDC := win.CreateDC(
		syscall.StringToUTF16Ptr("WINSPOOL"),
		syscall.StringToUTF16Ptr(printerName),
		nil,
		(*win.DEVMODE)(unsafe.Pointer(&devMode)),
	)
	if printerDC == 0 {
		return fmt.Errorf("无法应用打印机设置")
	}

	// 开始文档打印
	docInfo := win.DOCINFO{
		CbSize:       int32(unsafe.Sizeof(win.DOCINFO{})),
		LpszDocName:  syscall.StringToUTF16Ptr("全页照片"),
		LpszOutput:   nil,
		LpszDatatype: syscall.StringToUTF16Ptr("NT EMF 1.008"),
	}

	if win.StartDoc(printerDC, &docInfo) <= 0 {
		return fmt.Errorf("无法开始打印作业")
	}
	defer win.EndDoc(printerDC)

	// 开始页面打印
	if win.StartPage(printerDC) <= 0 {
		return fmt.Errorf("无法开始打印页面")
	}
	defer win.EndPage(printerDC)

	// 使用打印机DC
	dc := printerDC

	// 获取打印机的可打印区域
	// printableWidth := win.GetDeviceCaps(dc, win.HORZRES)
	// printableHeight := win.GetDeviceCaps(dc, win.VERTRES)
	// marginLeft := win.GetDeviceCaps(dc, win.PHYSICALOFFSETX)
	// marginTop := win.GetDeviceCaps(dc, win.PHYSICALOFFSETY)

	// 创建GDI+图形对象
	var graphics uintptr
	status, _, _ = gdipCreateFromHDC.Call(uintptr(dc), uintptr(unsafe.Pointer(&graphics)))
	if status != 0 {
		return fmt.Errorf("无法创建GDI+图形对象: %v", status)
	}
	defer gdipDeleteGraphics.Call(graphics)

	// 使用传入的参数设置图片位置和大小
	// 绘制图片
	status, _, _ = gdipDrawImageRectI.Call(
		graphics,
		image,
		uintptr(destX),
		uintptr(destY),
		uintptr(destWidth),
		uintptr(destHeight),
	)
	if status != 0 {
		return fmt.Errorf("无法绘制图片: %v", status)
	}

	return nil
}
